/**
 * 单层[感知器分类器](http://en.wikipedia.org/wiki/Perceptron)，用于对数值数组进行二分类（0/1）
 * @class
 * @example
 * // 创建分类器实例
 * var p = new PerceptronModel();
 * // 使用对角线决策边界数据进行训练
 * for (var i = 0; i < 5; i++) {
 *     p.train([1, 1], 1);
 *     p.train([0, 1], 0);
 *     p.train([1, 0], 0);
 *     p.train([0, 0], 0);
 * }
 * p.predict([0, 0]); // 0
 * p.predict([0, 1]); // 0
 * p.predict([1, 0]); // 0
 * p.predict([1, 1]); // 1
 */
class PerceptronModel {
    /*:: bias: number */
    /*:: weights: Array<number> */
    constructor() {
        // 模型权重系数数组（训练后生成）
        this.weights = [];
        // 偏置项（始终与1相乘的权重）
        this.bias = 0;
    }

    /**
     * **预测**：使用特征向量与权重数组的线性组合进行二分类预测
     *
     * @param {Array<number>} features 数值型特征数组
     * @returns {number} 当加权和超过0时返回1，否则返回0
     */
    predict(features) {
        // 仅当输入特征维度与模型参数匹配时执行预测
        if (features.length !== this.weights.length) {
            return null;
        }

        // 计算特征与权重的点积并加上偏置项
        let score = 0;
        for (let i = 0; i < this.weights.length; i++) {
            score += this.weights[i] * features[i];
        }
        score += this.bias;

        // 应用阶跃函数进行二分类
        return score > 0 ? 1 : 0;
    }

    /**
     * **训练**：使用特征-标签对更新模型参数（在线学习算法）
     *
     * @param {Array<number>} features 数值型特征数组
     * @param {number} label 二分类标签（0或1）
     * @returns {PerceptronModel} 返回当前对象以支持链式调用
     */
    train(features, label) {
        // 标签有效性验证
        if (label !== 0 && label !== 1) {
            throw new Error("无效标签：仅接受0或1的二分类标签");
        }

        // 特征维度变化时重新初始化模型参数
        if (features.length !== this.weights.length) {
            this.weights = [...features]; // 使用展开运算符进行数组复制
            this.bias = 1;
        }

        // 执行预测并计算误差
        const prediction = this.predict(features);
        if (prediction !== null && prediction !== label) {
            // 应用梯度下降算法更新参数
            const error = label - prediction;
            for (let i = 0; i < this.weights.length; i++) {
                this.weights[i] += error * features[i]; // 特征权重更新
            }
            this.bias += error; // 偏置项更新
        }
        return this;
    }
}

export default PerceptronModel;
